using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using AutoMapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using netCoreStudy.Express;
using Newtonsoft.Json;

namespace netCoreStudy.Entities.Base
{
	public class BaseService<T> : IBaseService<T> where T : BaseEntity
	{
		protected readonly ApiDbContext Context;
		protected readonly IMapper Mapper;
		private readonly ILogger<BaseService<T>> _logger;
		protected readonly DbSet<T> DbSet;

		public BaseService(ApiDbContext context, IMapper mapper,
			ILogger<BaseService<T>> logger)
		{
			Context = context ??
			          throw new ArgumentNullException(
				          nameof(context));
			Mapper = mapper;
			_logger = logger ?? throw new ArgumentNullException(nameof(logger));
			DbSet = Context.Set<T>();
		}

		public void Add(T model)
		{
			if (model == null)
				throw new ArgumentNullException(nameof(model));
			Context.Set<T>().Add(model);
		}

		public void AddRange(List<T> models)
		{
			if (models == null)
				throw new ArgumentNullException(nameof(models));
			Context.Set<T>().AddRange(models);
		}

		public void Update(T model)
		{
		}

		public void Remove(T model)
		{
			if (model == null)
				throw new ArgumentNullException(nameof(model));
			model.IsRemoved = true;
		}

		public void TrueRemove(T model)
		{
			if (model == null)
				throw new ArgumentNullException(nameof(model));
			Context.Remove(model);
		}

		public async Task<bool> SaveAsync()
		{
			// 返回值应该是返回数据库中受影响记录的行数。
			// 对于增加，返回的是增加成功的行数。
			// 对于更新，返回的时候成功更新了几行。
			// 对于删除，返回到底成功删除了几行。
			return await Context.SaveChangesAsync() > 0;
		}


		public async Task<bool> ExistByIdAsync(long id)
		{
			return
				await Context.Set<T>().AnyAsync(x => x.Id == id);
		}

		public bool ExistById(long id)
		{
			return Context.Set<T>().Any(x => x.Id == id);
		}


		public async Task<T> GetOneByIdAsync(long id)
		{
			return await GetAll()
				.FirstOrDefaultAsync(x => x.Id == id);
		}

		public IQueryable<T> GetAll()
		{
			return Context.Set<T>()
				.IncludeExp()
				.AsQueryable();
		}

		public IQueryable<T> GetAllSingle()
		{
			return Context.Set<T>()
				.AsQueryable();
		}

		public async Task<List<T>> GetAllByIdsAsync(long[] ids)
		{
			return await GetAll().Where(x => ids.Contains(x.Id)).ToListAsync();
		}


		public async Task<PageList<T>> GetPages(BaseParameter baseParameter)
		{
			IQueryable<T> query = GetAll()
				.WhereExp3(baseParameter)
				.OrderByExp(baseParameter);
			PageList<T> pageList = await PageList<T>.CreateAsync(
				query, baseParameter.PageIndex,
				baseParameter.PageSize);
			// _logger.LogInformation(pageList.JsonCW());
			return pageList;
		}

		public async Task<ResMsg<PageRes<TDto>>> GetPagesDto<TDto>(
			BaseParameter baseParameter)
		{
			PageList<T> pageList = await GetPages(baseParameter);
			List<TDto> dtos = Mapper.Map<List<TDto>>(pageList);
			ResMsg<PageRes<TDto>> resMsg = new ResMsg<PageRes<TDto>>(
				new PageRes<TDto>(
					pageList.PageIndex,
					pageList.PageSize,
					pageList.TotalCount,
					dtos
				));
			return resMsg;
		}
	}
}